home *** CD-ROM | disk | FTP | other *** search
/ FM Towns: Free Software Collection 10 / FM Towns Free Software Collection 10.iso / ms_dos / tool / mcfilter / mcfilter.c next >
Text File  |  1995-02-15  |  8KB  |  340 lines

  1. /*
  2.  
  3. MercuryFilter Version 1.00a for All MS-DOS Machines
  4. Copyright (c) 1995 Delmonta all rights reserved.
  5.  
  6. コンパイルについて:
  7.     浮動小数点演算は使用していませんので、printf関数は
  8.     doubleに対応していないサブセット版を使用してもかまいません。
  9. */
  10.  
  11. #include<ctype.h>
  12. #include<jstring.h>
  13. #include<stdarg.h>
  14. #include<stdio.h>
  15. #include<stdlib.h>
  16. #include<string.h>
  17.  
  18. /*****************************************************************************/
  19. /*                              下請けルーチン                               */
  20. /*****************************************************************************/
  21. #define    MEMBERSOF(array)    (sizeof(array)/sizeof((array)[0]))
  22.  
  23. static    char    Separators[] = " \t\n\v";
  24. static    int    Linepos = 0;
  25. /*--------------------------------エラー終了---------------------------------*/
  26. static    void    die(char *s,...)
  27. {
  28.     va_list    ap;
  29.  
  30.     fprintf(stderr,"%d:",Linepos);
  31.  
  32.     va_start(ap,s);
  33.     vfprintf(stderr,s,ap);
  34.     va_end(ap);
  35.  
  36.     exit(1);
  37. }
  38. /*--------------------文字列の両端の空白類をカットする-----------------------*/
  39. static    char    *chop(char *s)
  40. {
  41.     while    (isspace(*s))
  42.         s++;
  43.  
  44.     if    (*s!='\0')
  45.     {
  46.         char    *p = strchr(s,'\0');
  47.  
  48.         while    (isspace(*--p))
  49.             ;
  50.  
  51.         *(p+1) = '\0';
  52.     }
  53.  
  54.     return s;
  55. }
  56. /*-------------------エラー処理を含む文字列の二重化--------------------------*/
  57. static    char    *xstrdup(char *s)
  58. {
  59.     s = strdup(s);
  60.     if    (s!=NULL)
  61.         return s;
  62.  
  63.     die("メモリ不足です\n");
  64.     exit(1);
  65. }
  66. /*****************************************************************************/
  67. /*                             各キーワードの処理                            */
  68. /*---------------------------------------------------------------------------*/
  69. /* 各キーワードを処理する関数が0を返した場合、その行は出力されない           */
  70. /*****************************************************************************/
  71. static    int    Keywordnum = 0;
  72. static    int    Groupkey_num = 0;
  73.  
  74. static    char    *Keyword[32];
  75.  
  76. static    struct
  77. {
  78.     char    *name;
  79.     int    keywordid;
  80. } Groupkey[256];
  81. /*------------キーワードテーブルから指定されたキーワードを探す---------------*/
  82. /* 見つからなければエラー終了する。                                          */
  83. /*---------------------------------------------------------------------------*/
  84. static    int    find_keyword(char *p)
  85. {
  86.     int    i;
  87.  
  88.     for    (i=0 ; i<Keywordnum ; i++)
  89.     {
  90.         if    (stricmp(p,Keyword[i])==0)
  91.             return i;
  92.     }
  93.  
  94.     die("キーワード %s は定義されていません\n",p);
  95.     exit(1);
  96. }
  97. /*----------------グループキーテーブルからグループキーを探す-----------------*/
  98. /* 見つからなければ黙って-1を返す。                                          */
  99. /* 返すのは、配列Groupkeyの添え字ではなく、対応するKEYWORDの番号。           */
  100. /*---------------------------------------------------------------------------*/
  101. static    int    find_groupkey(char *p)
  102. {
  103.     int    i;
  104.  
  105.     for    (i=0 ; i<Groupkey_num ; i++)
  106.     {
  107.         if    (stricmp(p,Groupkey[i].name)==0)
  108.             return Groupkey[i].keywordid;
  109.     }
  110.  
  111.     return -1;
  112. }
  113. /*--------------------------KEYWORD(1);PROGRAM以前---------------------------*/
  114. static    int    cmd_keyword_def(char *dst,char *src)
  115. {
  116.     char    *p;
  117.  
  118.  
  119.     *dst = '\0';
  120.  
  121.     for    (p=jstrtok(src,Separators);p!=NULL;p=jstrtok(NULL,Separators))
  122.     {
  123.         Keyword[Keywordnum++] = xstrdup(p);
  124.         strcat(dst,p);
  125.         strcat(dst," ");
  126.     }
  127.  
  128.     return 1;
  129. }
  130. /*-------------------------KEYWORD(2);PROGRAM以後----------------------------*/
  131. static    int    cmd_keyword_ref(char *dst,char *src)
  132. {
  133.     char    *p;
  134.  
  135.     *dst = '\0';
  136.  
  137.     for    (p=jstrtok(src,Separators);p!=NULL;p=jstrtok(NULL,Separators))
  138.     {
  139.         int    n;
  140.  
  141.         n = find_groupkey(p);
  142.         if    (n>=0)
  143.             p = Keyword[n];
  144.         else
  145.             find_keyword(p);
  146.  
  147.         strcat(dst,p);
  148.         strcat(dst," ");
  149.     }
  150.  
  151.     return 1;
  152. }
  153. /*---------------------------------GROUP-------------------------------------*/
  154. static    int    cmd_group(char *dst,char *src)
  155. {
  156.     char    *p;
  157.     int    id;
  158.  
  159.     p = jstrtok(src,Separators);
  160.     if    (p==NULL)
  161.         return 0;
  162.  
  163.     id = find_keyword(p);
  164.     while    ((p=jstrtok(NULL,Separators))!=NULL)
  165.     {
  166.         if    (Groupkey_num==MEMBERSOF(Groupkey))
  167.             die("グループキーの数が多すぎます\n");
  168.  
  169.         if    (find_groupkey(p)>=0)
  170.             die("グループキー%sが二重に定義されています\n",p);
  171.  
  172.         Groupkey[Groupkey_num].name      = xstrdup(p);
  173.         Groupkey[Groupkey_num].keywordid = id;
  174.  
  175.         Groupkey_num++;
  176.     }
  177.     return 0;
  178. }
  179. /*****************************************************************************/
  180. /*                             メインプログラム                              */
  181. /*****************************************************************************/
  182. #define    KEYWORD_DEF    0
  183. #define    KEYWORD_REF    1
  184. #define    GROUP        2
  185.  
  186. #define    THROUGH        3
  187. #define    CUT        4
  188.  
  189. static    int    (*Command[3])(char *dst,char *src) =
  190.     {cmd_keyword_def,cmd_keyword_ref,cmd_group};
  191. /*-----------------------------コマンド名の解析------------------------------*/
  192. static    int    getcommandid(char *s)
  193. {
  194.     static    int    isafterprogram = 0;
  195.  
  196.     static    int    cutnum = 0;        /* 削除するキーワードの数   */
  197.     static    int    throughnum = 6;        /* 素通しするキーワードの数 */
  198.  
  199.     static    char    *cuttable[256];        /* 削除するキーワード       */
  200.     static    char    *throughtable[256] =    /* 素通しするキーワード     */
  201.         {"DRIVE","MAKE","DIR","README","MANUAL","COPY"};
  202.  
  203.     int    i;
  204.  
  205.     strupr(s);
  206.  
  207.     if    (stricmp(s,"KEYWORD")==0)
  208.     {
  209.         if    (isafterprogram)
  210.             return KEYWORD_REF;
  211.         else
  212.             return KEYWORD_DEF;
  213.     }
  214.     else if    (stricmp(s,"GROUP")==0)
  215.         return GROUP;
  216.     else if    (stricmp(s,"PROGRAM")==0)
  217.     {
  218.         isafterprogram = 1;
  219.         return THROUGH;
  220.     }
  221.  
  222.     for    (i=0 ; i<cutnum ; i++)
  223.     {
  224.         if    (stricmp(s,cuttable[i])==0)
  225.             return CUT;
  226.     }
  227.  
  228.     for    (i=0 ; i<throughnum ; i++)
  229.     {
  230.         if    (stricmp(s,throughtable[i])==0)
  231.             return THROUGH;
  232.     }
  233.  
  234. rep:
  235.     fprintf(stderr,    "未定義のコマンドです %s\n"
  236.             "中止<A>,素通し<T>,削除<C>?",s);
  237.  
  238.     i = getche();
  239.     putc('\n',stderr);
  240.  
  241.     switch    (i)
  242.     {
  243.     case 'A':
  244.     case 'a':
  245.         exit(1);
  246.     case 'T':
  247.     case 't':
  248.         if    (throughnum == MEMBERSOF(throughtable))
  249.             die("THROUGHキーワードの数が多すぎます\n");
  250.         throughtable[throughnum++] = xstrdup(s);
  251.         return THROUGH;
  252.     case 'C':
  253.     case 'c':
  254.         if    (cutnum==MEMBERSOF(cuttable))
  255.             die("CUTキーワードの数が多すぎます\n");
  256.         cuttable[cutnum++] = xstrdup(s);
  257.         return CUT;
  258.     default:
  259.         goto rep;
  260.     }
  261. }
  262. /*-----------------------------オプションの解析------------------------------*/
  263. static    void    option(char *s)
  264. {
  265.     switch    (s[1])
  266.     {
  267.     case 'H':
  268.     case 'h':    /* ヘルプは、明示的にオプションを指定して出力する */
  269.     case '?':    /* ものだから、出力先はstdoutにする               */
  270.         printf("MCFILTER ファイル名\n\n");
  271.         break;
  272.     default:
  273.         die("不正なオプションです %s\n",s);
  274.     }
  275. }
  276. /*------------------------------メインルーチン-------------------------------*/
  277. extern    int    main(int argc,char **argv)
  278. {
  279.     FILE    *fpi;
  280.  
  281.     char    buf[2][512];
  282.  
  283.     #define    fpo    stdout
  284.  
  285.     while    (++argv,--argc)
  286.     {
  287.         if    (**argv=='-')
  288.         {
  289.             option(*argv);
  290.             continue;
  291.         }
  292.  
  293.         if    ((fpi=fopen(*argv,"r"))==NULL)
  294.         {
  295.             fprintf(stderr,"%sがオープンできません\n",*argv);
  296.             exit(1);
  297.         }
  298.  
  299.         Linepos = 0;
  300.  
  301.         while    (fgets(buf[0],sizeof(buf[0]),fpi)!=NULL)
  302.         {
  303.             char    *p,*q;
  304.             int    id;
  305.  
  306.             Linepos++;
  307.  
  308.             p = chop(buf[0]);
  309.             if    (*p=='\0' || *p=='#')    /* 空行・コメント行の削除 */
  310.                 continue;
  311.  
  312.             q = strchr(p,':');
  313.             if    (q==NULL)
  314.                 die("不正な行です  %s\n",p);
  315.  
  316.             *q = '\0';
  317.             p = chop(p);
  318.             q = chop(q+1);
  319.  
  320.             id = getcommandid(p);
  321.             if    (id==CUT)
  322.                 continue;
  323.             else if    (id!=THROUGH)
  324.             {
  325.                 if    (!Command[id](buf[1],q))
  326.                     continue;
  327.  
  328.                 q = buf[1];
  329.             }
  330.  
  331.             fprintf(fpo,"%s:%s\n",p,q);
  332.         }
  333.  
  334.         fclose(fpi);
  335.     }
  336.  
  337.     return 0;
  338. }
  339. /*----------------------------End of MCFILTER.C------------------------------*/
  340.